#ifndef _s_H_
#define _s_H_

#include <vector>
#include <string>

#define NEW_RTTI_PARAMETER(tp, classtype, ...) new rtti::s_ ## tp ## _Parameter < classtype > (__VA_ARGS__)
#define NEW_RTTI_TEMPLATE_PARAMETER(tp, tmp, classtype, ...) new rtti::s_ ## tp ## _Parameter < tmp, classtype > (__VA_ARGS__)
#define NEW_RTTI_CLASS_PARAMETER(...) new rtti::sClassParameter(__VA_ARGS__)
#define REGISTER_RTTI(objname, slctr, param) list.push_back(new rtti::sInfo(objname, new rtti::s_ ## slctr ## _Selector(param)))

namespace sgui
{
namespace rtti
{
	typedef enum {
		PIF_CHILD			= (1 << 0),
		PIF_EDITOR			= (1 << 1),
		PIF_SELECT			= (1 << 2)
	} EPIFlag;
	typedef unsigned char EPIFlags;

	class sObject;
	class sInfo;

	typedef std::vector<sInfo*> sInfoList;

	class sParameterInterface
	{
	public:
		virtual void set(const std::wstring& data) = 0;
		virtual const std::wstring get() = 0;
		virtual const sInfoList* getChild() { return NULL; }

		virtual const EPIFlags getFlags() const = 0;
	};

	template < typename T, class C >
	class sParameter: public sParameterInterface
	{
	public:
		typedef void (C::*SETTER)(const T& value);
		typedef const T& (C::*GETTER)() const;
	private:
		C*			m_obj;
		SETTER		m_setter;
		GETTER		m_getter;
	protected:
		void _set(const T& t) { (m_obj->*m_setter)(t); }
		const T& _get() { return (m_obj->*m_getter)(); }
		const EPIFlags getFlags() const { return 0; }
	public:
		sParameter(C* obj, SETTER setter, GETTER getter) :
		  m_obj(obj),
		  m_setter(setter),
		  m_getter(getter)
	    {}
	};

	template <class C>
	class s_STRING_Parameter : public sParameter<std::wstring, C>
	{
	public:
		void set(const std::wstring& data)
		{
			_set(data);
		}
		const std::wstring get()
		{
			return _get();
		}
		s_STRING_Parameter(C* obj, SETTER setter, GETTER getter) :
			sParameter(obj, setter, getter)
		{}
	};

	template < typename T, class C >
	class s_INT_Parameter : public sParameter <T, C>
	{
	public:
		void set(const std::wstring& data)
		{
			_set((T)_wtof(data.c_str()));
		}
		const std::wstring get()
		{
			std::wstringstream wss;
			wss << _get();
			return wss.str();
		}
		s_INT_Parameter(C* obj, SETTER setter, GETTER getter) : sParameter(obj, setter, getter) {};
	};

	template < typename T, class C >
	class s_ENUM_Parameter : public sParameter <T, C>
	{
	public:
		void set(const std::wstring& data)
		{
			_set((T)_wtoi(data.c_str()));
		}
		const std::wstring get()
		{
			std::wstringstream wss;
			wss << (T)_get();
			return wss.str();
		}
		s_ENUM_Parameter(C* obj, SETTER setter, GETTER getter) : sParameter(obj, setter, getter) {};
	};

	template < class C >
	class s_BOOL_Parameter : public sParameter <bool, C>
	{
	public:
		void set(const std::wstring& data)
		{
			_set(data == L"true");
		}
		const std::wstring get()
		{
			return _get() ? L"true" : L"false";
		}
		s_BOOL_Parameter(C* obj, SETTER setter, GETTER getter) : sParameter(obj, setter, getter) {};
	};

	class sSelector
	{
	private:
		sParameterInterface*	m_param;
	public:
		virtual const std::wstring getValue() = 0;
		virtual void setComponent() = 0;

		sParameterInterface* getParameter();
		sSelector(sParameterInterface* param);
	};

	class s_TEXT_Selector : public sSelector
	{
	public:
		const std::wstring getValue();
		void setComponent();
		s_TEXT_Selector(sParameterInterface* param);
	};

	class sInfo
	{
	private:
		std::wstring			m_name;
		sSelector*				m_selector;
		sParameterInterface*	m_parameter;
	public:
		const std::wstring& getName();
		sParameterInterface*	getParameter();

		sInfo(const std::wstring& name, sSelector* selector);
		~sInfo();
	};

	class sClassParameter : public sParameterInterface
	{
	private:
		sObject&			m_obj;
		sInfoList			m_list;
	public:
		void set(const std::wstring& data);
		const std::wstring get();
		const EPIFlags getFlags() const;
		
		const sInfoList* getChild();

		sClassParameter(sObject& obj);
	};
};
};

#endif